#include "trace.h"

#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <stdarg.h>

#define STDERRFORMAT "[%s] %s: %s(+%d): %s"

static trace_level_t TRACE_LEVEL = T_DEBUG | T_INFO | T_WARN | T_ERR | T_FATAL;

static const char * trace_to_text(trace_level_t level)
{
	const char * const trace_text[] = {
		"FATAL",
		"ERROR",
		"WARN",
		"INFO",
		"DEBUG",
	};
	return trace_text[ilogb((double) level)];
}

void set_trace_level(trace_level_t l)
{
    TRACE_LEVEL = l;
}

void trace(trace_level_t level, const char * function, int line,
        const char *formatstring, ...)
{
	/* Return now if we're not logging anything. */
	if (level & TRACE_LEVEL) {
        va_list ap, cp;
        char *message = NULL;
        size_t l;

        va_start(ap, formatstring);
        va_copy(cp, ap);
        vasprintf(&message, formatstring, cp);
        va_end(cp);

        l = strlen(message);
        
        if (message[l] == '\n')
            message[l] = '\0';

        if (level & TRACE_LEVEL) {
            time_t now = time(NULL);
            struct tm tmp;
            char date[32];

            memset(date, 0, sizeof(date));
            localtime_r(&now, &tmp);
            strftime(date, 32, "%H:%M:%S", &tmp);

            fprintf(stdout, STDERRFORMAT, date, trace_to_text(level), function, 
                    line, message);
     
            if (message[l] != '\n')
                fprintf(stdout, "\n");
            fflush(stdout);
        }

        free(message);

        if (level == T_FATAL) {
            exit(1);
        }
    } else {
		return;
    }

}

